home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
display.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
39KB
|
1,661 lines
/*
* $Id: display.c,v 0.91 1994/02/20 00:52:56 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* Display image defined in the image structure. Code is geared for maximum
* speed. Also, some misc. routines that does mode settting and screen
* clearing.
*
* Area bounded by im->{xi,yi,xf,yf} are the (true) image locations relative to
* window. In the case where the image is larger than window, part of image
* will be invisible (outside the viewing area). To speed up display, pxi,
* pyi, pxf, pyf are guaranteed to be within the window even if image is
* larger than window and degenerates into im->{xi,yi,xf,yf} if image is
* smaller than window. px0 and py0 indicate the offset into the raster from
* where the image starts, e.g., if displaying a pixel at (x,y), image
* should be starting from (image + (y+py0) * width + x+px0). The other uses
* of pxi,pyi etc. are when the image is panned, and part of the image is
* invisible.
*
* The following relation MUST holds for panning etc.
*
* im->xf + im->xoff2 - (im->xi + im->xoff2) + 1 == Min(win_w, im->w);
*
* Note: for rectwrite, the screen localtions are specified by the parameters
* and therefore, the x offset equals x-pxi+im->xoff1.
*
*/
#if !defined(lint) && defined(F_ID)
char *id_dis = "$Id: display.c,v 0.91 1994/02/20 00:52:56 zhao Pre-Release $";
#endif
#include "bit.h"
#include "extern.h"
#include "dmalloc.h"
/*******************************************************************
* On some machines (4.0.5H ?), if the image is larger than the physical
* screen, colormapped image will not display correctly.
* Define PWRITE_BUG to enable workaround code
*
* To workaround code does not work either, something is wrong
* with bit ....
*******************************************************************/
#define NO_PWRITE_BUG
#ifndef NO_PWRITE_BUG
#define PWRITE_BUG
#endif
/*****************************************************************
* Note that ALL windows under BIT process have the same display mode
* FORM window is not considered to be part of BIT process because
* it takes care of its own redraws
*******************************************************************/
/********************** Local variables ***************************/
static int rgbmode; /* current window mode */
static short bkindex = BKINDEX; /* background color in CI mode */
static rgba_t bkcolor; /* bkcolor in RGB mode */
static int bkr, bkg, bkb; /* r,g,b for BK */
/********************************************************
* Set background color, but don't activate
********************************************************/
void
set_bk_color(rgba_t p)
{
bkcolor = p;
CPACK2RGB(p, bkr, bkg, bkb);
}
/********************************************************
* Choose display mode according to image type and hardware
* characteristics.
********************************************************/
#include "gl/get.h"
/*******************************************************************
* Switch current display mode to RGB, also matching doublebuffer
* request.
******************************************************************/
void
set_rgb_mode(void)
{
int mode = getdisplaymode();
/* re-config if mode mismatch or double/single buffer mismtach */
if (!((mode == DMRGB && !double_buf) ||
(mode == DMRGBDOUBLE && double_buf)))
{
M_info("Display", "Switching to RGBmode");
RGBmode();
(double_buf ? doublebuffer : singlebuffer) ();
gconfig();
rgbmode = 1;
clear_screen(win_id, 1);
}
}
void
set_cmap_mode(void)
{
int mode = getdisplaymode();
if (!((mode == DMSINGLE && !double_buf) ||
(mode == DMDOUBLE && double_buf)))
{
M_info("Display", "Switching to CMAPmode");
cmode();
(double_buf ? doublebuffer : singlebuffer) ();
gconfig();
rgbmode = 0;
clear_screen(win_id, 1);
}
}
void
set_display_mode(IPTR im)
{
CMPTR map = im->cmap;
set_current_window(win_id);
if (IS_CPACK(im))
{
set_rgb_mode();
}
else
{
set_cmap_mode();
/* writemask(im->cmap->colors-1); */
set_cmap(map);
}
}
/*********************************************************
* Clear current window
*********************************************************/
static void
clear_it(void)
{
if (rgbmode)
cpack(bkcolor);
else
{
mapcolor(bkindex, bkr, bkg, bkb);
color(bkindex);
}
clear();
}
/************************************************************
* Clear specified window
************************************************************/
void
clear_screen(long win, int show)
{
long owin = winget();
int dispmode = rgbmode;
set_current_window(win);
reshapeviewport();
rgbmode = getdisplaymode();
rgbmode = (rgbmode == DMRGB || rgbmode == DMRGBDOUBLE);
clear_it();
rgbmode = dispmode;
if (show && double_buf)
{
swapbuffers();
clear_it();
}
set_current_window(owin);
}
/*****************************************************************
* Clear the region between rectangle r1 and r2.
*****************************************************************/
void
clear_between_rect(const Rect_t * r1, const Rect_t * r2)
{
int xf1 = r1->x + r1->w - 1;
int yf1 = r1->y + r1->h - 1;
int xf2 = r2->x + r2->w - 1;
int yf2 = r2->y + r2->h - 1;
set_color_bk();
/* left */
if (r1->x > r2->x)
rectfi(r2->x, r2->y, r1->x - 1, yf2);
/* right */
if (xf1 < xf2)
rectfi(xf1 + 1, r2->y, xf2, yf2);
/* bottom */
if (r1->y > r2->y)
rectfi(r1->x - 1, r2->y, xf1 + 1, r1->y - 1);
/* top */
if (yf1 < yf2)
rectfi(r1->x - 1, yf1 + 1, xf1 + 1, yf2);
}
/******************************************************************
* Clear the regions outside a rectangle and clips at the window
* boundary. Could be implemented as clear_between_rect.
******************************************************************/
void
clear_outside_rect(const Rect_t * r)
{
int xf = r->x + r->w - 1;
int yf = r->y + r->h - 1;
set_color_bk();
/* left */
if (r->x > 0)
rectfi(0, 0, r->x - 1, win_h - 1);
/* right */
if (xf < win_w - 1)
rectfi(xf + 1, 0, win_w - 1, win_h - 1);
/* bottom */
if (r->y > 0)
rectfi(r->x - 1, 0, xf + 1, r->y - 1);
/* top */
if (yf < win_h - 1)
rectfi(r->x - 1, yf + 1, xf + 1, win_h - 1);
}
/***************************************************************
* Set current color.
***************************************************************/
void
Color(rgba_t col, int ci)
{
if (rgbmode)
cpack(col);
else
color(ci);
}
/*****************************************************************
* Color is given as 4 element array: the first three are RGB
* and the fourth is CI
****************************************************************/
void
Color4(int *c)
{
if (rgbmode)
cpack(Pack(c[0], c[1], c[2]));
else
color(c[3]);
}
/***************************************************************
* activate current background color
***************************************************************/
void
set_color_bk(void)
{
Color(bkcolor, bkindex);
}
/*********************************************************
* Clear a rectanglular region to current bk color
********************************************************/
void
rect_clear(long win, int xi, int xf, int yi, int yf)
{
set_current_window(win);
viewport(xi, xf, yi, yf);
clear_it();
}
/*********************************************************
* Pixel blind rectwrite. Should not be called by any of
* of the displaying related routines, it is meant for
* subimage handling
********************************************************/
void
Rectwrite(int xi, int yi, int xf, int yf, void *r)
{
frontbuffer(1);
if (rgbmode)
lrectwrite(xi, yi, xf, yf, r);
else
rectwrite(xi, yi, xf, yf, r);
frontbuffer(!double_buf);
}
/****************************************************************
* Pixel type blind framebuffer read
***************************************************************/
long
Rectread(int xi, int yi, int xf, int yf, void *r)
{
return rgbmode ?
lrectread(xi, yi, xf, yf, r) : rectread(xi, yi, xf, yf, r);
}
/************************************************************
* All display related routines, variables
************************************************************/
static int pxi, pxf, px0, pyi, pyf, py0;
static long xy[2];
static rgba_t **rgba;
static Colorindex **cind;
static float zoomx, zoomy;
#define DISP_ROW(y,x1,x2,f,ras) \
f(x1,y,x2,y,(ras[y+py0] + (x1 + im->xoff1 - pxi )))
/**************************************************************
* display from top to bottom
**************************************************************/
static void
ds_down(IPTR im)
{
register int j;
if (IS_CPACK(im))
{
for (j = pyf; j >= pyi; j--)
DISP_ROW(j, pxi, pxf, lrectwrite, rgba);
}
else
{
for (j = pyf; j >= pyi; j--)
DISP_ROW(j, pxi, pxf, rectwrite, cind);
}
}
/*************************************************************
* display from bottom to top
************************************************************/
static void
ds_up(IPTR im)
{
register int j;
if (IS_CPACK(im))
{
for (j = pyi; j <= pyf; j++)
DISP_ROW(j, pxi, pxf, lrectwrite, rgba);
}
else
{
for (j = pyi; j <= pyf; j++)
DISP_ROW(j, pxi, pxf, rectwrite, cind);
}
}
/************************************************************************
* Default. Write pixels in one scoop
************************************************************************/
static void
ds_block(IPTR im)
{
if (zoomx > 1.1 || zoomy > 1.1)
{
if (IS_CPACK(im))
lrectwrite(im->xi, im->yi, im->xi + im->w - 1,
im->yi + im->h - 1, rgba[0]);
else
rectwrite(im->xi, im->yi, im->xi + im->w - 1,
im->yi + im->h - 1, cind[0]);
return;
}
if (IS_CPACK(im))
{
if (im->w < (win_w + 400) && im->xoff1 < 400 && im->xoff2 < 400)
{
lrectwrite(im->xi, pyi, im->xf, pyf, rgba[im->yoff1]);
}
else
{
ds_up(im);
}
return;
}
/* must be CI and need to take care of the bug */
#ifdef PWRITE_BUG
if ((im->xi + win_xo) > 0 && im->xf < getgdesc(GD_XPMAX))
#else
if (im->w < (win_w + 400) && im->xoff1 < 400 && im->xoff2 < 400)
#endif
{
rectwrite(im->xi, pyi, im->xf, pyf, cind[im->yoff1]);
}
else
{
ds_up(im);
}
}
/************************************************************
* explode from center to top and bottom
**************************************************************/
static void
ds_ctb(IPTR im)
{
register int j, hh = (pyf - pyi + 1) / 2, cc = (pyf + pyi) / 2;
if (IS_CPACK(im))
{
for (j = 0; j <= hh; j++)
{
if (cc - j >= pyi)
DISP_ROW(cc - j, pxi, pxf, lrectwrite, rgba);
if (cc + j <= pyf)
DISP_ROW(cc + j, pxi, pxf, lrectwrite, rgba);
}
}
else
{
for (j = 0; j <= hh; j++)
{
if (cc - j >= pyi)
DISP_ROW(cc - j, pxi, pxf, rectwrite, cind);
if (cc + j <= pyf)
DISP_ROW(cc + j, pxi, pxf, rectwrite, cind);
}
}
}
/******************************************************************
* explode from top and bottom towards the center line
******************************************************************/
static void
ds_tbc(IPTR im)
{
register int j, hh = (pyf - pyi + 1) / 2;
if (IS_CPACK(im))
{
for (j = 0; j <= hh; j++)
{
DISP_ROW(pyi + j, pxi, pxf, lrectwrite, rgba);
DISP_ROW(pyf - j, pxi, pxf, lrectwrite, rgba);
}
}
else
{
for (j = 0; j <= hh; j++)
{
DISP_ROW(pyi + j, pxi, pxf, rectwrite, cind);
DISP_ROW(pyf - j, pxi, pxf, rectwrite, cind);
}
}
}
#define DN_RSEG(y1,y2,s,f,ras) \
do { \
for (i=y1;i>=y2;i-=s) { DISP_ROW(i,pxi,pxf,f,ras);} \
} while (ZERO)
/**********************************************************
* GIF interlace
**********************************************************/
static void
ds_gint(IPTR im)
{
register int i;
if (IS_CPACK(im))
{
DN_RSEG(pyf, pyi, 8, lrectwrite, rgba);
DN_RSEG(pyf - 4, pyi, 8, lrectwrite, rgba);
DN_RSEG(pyf - 2, pyi, 4, lrectwrite, rgba);
DN_RSEG(pyf - 1, pyi, 2, lrectwrite, rgba);
}
else
{
DN_RSEG(pyf, pyi, 8, rectwrite, cind);
DN_RSEG(pyf - 4, pyi, 8, rectwrite, cind);
DN_RSEG(pyf - 2, pyi, 4, rectwrite, cind);
DN_RSEG(pyf - 1, pyi, 2, rectwrite, cind);
}
}
/*************************************************************
* nice interlace
*************************************************************/
static void
ds_int(IPTR im)
{
register int i;
if (IS_CPACK(im))
{
DN_RSEG(pyf, pyi, 4, lrectwrite, rgba);
DN_RSEG(pyf - 2, pyi, 4, lrectwrite, rgba);
DN_RSEG(pyf - 3, pyi, 4, lrectwrite, rgba);
DN_RSEG(pyf - 1, pyi, 4, lrectwrite, rgba);
}
else
{
DN_RSEG(pyf, pyi, 4, rectwrite, cind);
DN_RSEG(pyf - 2, pyi, 4, rectwrite, cind);
DN_RSEG(pyf - 3, pyi, 4, rectwrite, cind);
DN_RSEG(pyf - 1, pyi, 4, rectwrite, cind);
}
}
#define DISP_COL(x,y1,y2,f,ras) \
do { \
register int k_, xx_; \
xy[0]= x; xx_= x + px0; \
for (k_ = y1; k_ <= y2; ++k_) { \
xy[1]= k_; f(ras[k_+py0][xx_]); v2i(xy); \
} \
} while (ZERO)
/*****************************************************************
* display from left to right
*****************************************************************/
static void
ds_left(IPTR im)
{
register int i;
bgnpoint();
if (IS_CPACK(im))
{
for (i = pxi; i <= pxf; i++)
DISP_COL(i, pyi, pyf, cpack, rgba);
}
else
{
for (i = pxi; i <= pxf; i++)
DISP_COL(i, pyi, pyf, color, cind);
}
endpoint();
}
/***************************************************************
* Display from right to left
***************************************************************/
static void
ds_right(IPTR im)
{
register int i;
bgnpoint();
if (IS_CPACK(im))
{
for (i = pxf; i >= pxi; i--)
DISP_COL(i, pyi, pyf, cpack, rgba);
}
else
{
for (i = pxf; i >= pxi; i--)
DISP_COL(i, pyi, pyf, color, cind);
}
endpoint();
}
#define LR_CSEG(x1,x2,s,f,ras) \
for ( i= x1; i<= x2; i += s) \
DISP_COL(i,pyi,pyf,f,ras)
/*****************************************************************
* columnwise interlace
******************************************************************/
static void
ds_cint(IPTR im)
{
register int i;
bgnpoint();
if (IS_CPACK(im))
{
LR_CSEG(pxi, pxf, 4, cpack, rgba);
LR_CSEG(pxi + 2, pxf, 4, cpack, rgba);
LR_CSEG(pxi + 1, pxf, 4, cpack, rgba);
LR_CSEG(pxi + 3, pxf, 4, cpack, rgba);
}
else
{
LR_CSEG(pxi, pxf, 4, color, cind);
LR_CSEG(pxi + 2, pxf, 4, color, cind);
LR_CSEG(pxi + 1, pxf, 4, color, cind);
LR_CSEG(pxi + 3, pxf, 4, color, cind);
}
endpoint();
}
/***********************************************************
* explode leftright from center
************************************************************/
static void
ds_clr(IPTR im)
{
register int i, ww = (pxf - pxi + 1) / 2, cc = (pxf + pxi) / 2;
bgnpoint();
if (IS_CPACK(im))
{
for (i = 0; i <= ww; i++)
{
if (cc - i >= pxi)
DISP_COL(cc - i, pyi, pyf, cpack, rgba);
if (cc + i <= pxf)
DISP_COL(cc + i, pyi, pyf, cpack, rgba);
}
}
else
{
for (i = 0; i <= ww; i++)
{
if (cc - i >= pxi)
DISP_COL(cc - i, pyi, pyf, color, cind);
if (cc + i <= pxf)
DISP_COL(cc + i, pyi, pyf, color, cind);
}
}
endpoint();
}
/************************************************************
* explode left right towards the center
************************************************************/
static void
ds_lrc(IPTR im)
{
register int i, ww = (pxf - pxi + 1) / 2;
bgnpoint();
if (IS_CPACK(im))
{
for (i = 0; i <= ww; i++)
{
DISP_COL(pxi + i, pyi, pyf, cpack, rgba);
DISP_COL(pxf - i, pyi, pyf, cpack, rgba);
}
}
else
{
for (i = 0; i <= ww; i++)
{
DISP_COL(pxi + i, pyi, pyf, color, cind);
DISP_COL(pxf - i, pyi, pyf, color, cind);
}
}
endpoint();
}
/* macros that displays rectangularly towards the center */
#define RDISP_RECT(x1,y1,x2,y2,rf,cf,ras) \
do { \
DISP_ROW(y1,x1,x2,rf,ras); \
DISP_ROW(y2,x1,x2,rf,ras); \
bgnpoint(); \
DISP_COL(x1,y1,y2,cf,ras); \
DISP_COL(x2,y1,y2,cf,ras); \
endpoint(); \
} while (ZERO)
/*****************************************************************
* Display rectangularly
*****************************************************************/
static void
ds_rec1(IPTR im)
{
register int m = 0, hh = (pyf - pyi + 1) / 2, ww = (pxf - pxi + 1) / 2;
register int xx1 = pxi, xx2 = pxf, yy1 = pyi, yy2 = pyf;
if (IS_CPACK(im))
{
do
{
RDISP_RECT(xx1, yy1, xx2, yy2, lrectwrite, cpack, rgba);
xx1++;
yy1++;
xx2--;
yy2--;
m++;
}
while (m <= hh || m <= ww);
}
else
{
do
{
RDISP_RECT(xx1, yy1, xx2, yy2, rectwrite, color, cind);
xx1++;
yy1++;
xx2--;
yy2--;
m++;
}
while (m <= hh || m <= ww);
}
}
/*************************************************************
* display rectangularly from the center
**************************************************************/
static void
ds_rec2(IPTR im)
{
int ch = (pyf + pyi) / 2, cw = (pxf + pxi) / 2;
register int m = 0, hh = (pyf - pyi + 1) / 2, ww = (pxf - pxi + 1) / 2;
register int xx1 = cw, xx2 = cw, yy1 = ch, yy2 = ch;
if (IS_CPACK(im))
{
do
{
RDISP_RECT(xx1, yy1, xx2, yy2, lrectwrite, cpack, rgba);
xx1 = (xx1 <= pxi) ? pxi : xx1 - 1;
yy1 = (yy1 <= pyi) ? pyi : yy1 - 1;
xx2 = (xx2 >= pxf) ? pxf : xx2 + 1;
yy2 = (yy2 >= pyf) ? pyf : yy2 + 1;
m++;
}
while (m <= hh || m <= ww);
}
else
{
do
{
RDISP_RECT(xx1, yy1, xx2, yy2, rectwrite, color, cind);
xx1 = (xx1 <= pxi) ? pxi : xx1 - 1;
yy1 = (yy1 <= pyi) ? pyi : yy1 - 1;
xx2 = (xx2 >= pxf) ? pxf : xx2 + 1;
yy2 = (yy2 >= pyf) ? pyf : yy2 + 1;
m++;
}
while (m <= hh || m <= ww);
}
}
/************************************************************
* blend two streams: c = s * a + ( 1 - s) * b
***********************************************************/
static int blend_buf[2 * PCMAX + 3];
static void
blend_mat(register rgba_t *c, register rgba_t *a, register rgba_t *b,
register long total, register float s)
{
register int r1, g1, b1;
register int r2, g2, b2;
register int r3, g3, b3;
register rgba_t *cs;
register int *lut = blend_buf;
int i;
/* calculate the lookup table */
lut += PCMAXV;
for (i = -PCMAXV; i < PCMAX; i++)
lut[i] = (s * i);
/* blend */
for (cs = c + total; c < cs; c++, a++, b++)
{
Unpack(*a, r1, g1, b1);
Unpack(*b, r2, g2, b2);
r3 = *(lut + r1 - r2) + r2;
g3 = *(lut + g1 - g2) + g2;
b3 = *(lut + b1 - b2) + b2;
*c = Pack(r3, g3, b3);
}
}
/****************************************************************
* slowly fade into new picture
****************************************************************/
static void
ds_fade(IPTR im)
{
rgba_t **old, **new, **blend;
int nstep = 25;
float f, df;
const Rect_t *ir, *wr, *ur;
/* fade can only be done to RGB images */
if (IS_CI(im))
{
ds_block(im);
return;
}
/* find the dimension of exposed part of the image */
wr = make_rect(0, 0, win_w - 1, win_h - 1);
ur = union_rect(ir = img_rect(im), wr);
/* grab all the memory we needed before proceed */
if (!(old = get_mat(ur->h, ur->w, sizeof(rgba_t))))
{
ds_block(im);
return;
}
/* get the current image on screen */
lrectread(ur->x, ur->y, ur->x + ur->w - 1, ur->y + ur->h - 1, old[0]);
/*
* matrix for new image: if the new image is completely exposed, no need
* to allocate a matrix for the exposed part
*/
new = (equal_rect(ir, ur) ? im->mraster :
get_subimage(im, ur->x, ur->y, ur->w, ur->h));
if (!new)
{
ds_block(im);
return;
}
blend = get_mat(ur->h, ur->w, sizeof(rgba_t));
/* adjust steps: if image is large, decrease nstep, otherwise too slow */
nstep = (1600.0 / (im->h + im->w) * nstep);
df = 1.0 / nstep;
/* write the first (0) blend immediately, looks faster */
set_current_window(win_id);
clear_outside_rect(ur);
lrectwrite(ur->x, ur->y, ur->x + ur->w - 1, ur->y + ur->h - 1, old[0]);
frontbuffer(0);
/* simply blend the two images: b = a * old + (1-a) * new */
for (f = 1.0 - df; f >= 0.0; f -= df)
{
blend_mat(blend[0], old[0], new[0], ur->w * ur->h, f);
lrectwrite(ur->x, ur->y,
ur->x + ur->w - 1, ur->y + ur->h - 1, blend[0]);
swapbuffers();
check_emergency();
}
/*
* need to do this to show the complete pictures as blending might have
* errors due to floating point operation
*/
ds_block(im);
free_mat(blend);
free_mat(old);
if (new != im->mraster)
free_mat(new);
}
/************************************************************
* Spark fade
***********************************************************/
static short *msparkle;
static int max_sp;
/** Load sparkle data. should generate this on the fly .... ***/
static int
load_sparkle(void)
{
FILE *fp = get_HELPfile_fp("sparkle.dat", "r");
int mm;
short aa;
static int warned;
if (!fp)
{
if (!warned)
{
Bark("LoadSPData", "BadOpen");
warned = 1;
}
return -1;
}
fread(&aa, sizeof(short), 1, fp);
max_sp = aa;
mm = max_sp * max_sp;
msparkle = malloc(sizeof(short) * (mm + 1));
fread(msparkle, sizeof(short), mm, fp);
(void) fclose(fp);
return 0;
}
/************************************************************
* Actually do the sparkle fade
************************************************************/
static void
ds_sprkl(IPTR im)
{
static int first = 1;
register int cellx, celly;
register int i1, j1, xx1, xx2, yy1, yy2;
register int i;
if (first)
first = load_sparkle();
if (first || !msparkle)
{
ds_block(im);
return;
}
cellx = im->w / max_sp + ((im->w % max_sp) != 0);
celly = im->h / max_sp + ((im->h % max_sp) != 0);
for (i = 0; i < (max_sp * max_sp); i++)
{
i1 = msparkle[i] / max_sp;
j1 = msparkle[i] % max_sp;
xx1 = im->xi + i1 * cellx;
yy1 = im->yi + j1 * celly;
xx2 = xx1 + cellx;
yy2 = yy1 + celly;
if (xx2 > im->xf)
xx2 = im->xf;
if (yy2 > im->yf)
yy2 = im->yf;
if (xx2 > xx1 && yy2 > yy1)
draw_subimage(im, xx1, yy1, xx2 - xx1 + 1, yy2 - yy1 + 1);
}
}
/******************************************************************
* If image is larger than screen or its position not conform to the
* positioning requirememt, this routine will be called.
*****************************************************************/
static void
positioning_image(IPTR im)
{
im->xoff1 = (im->xi < 0) ? -im->xi : 0;
im->xoff2 = (im->xf > win_w) ? (win_w - im->xf - 1) : 0;
im->yoff1 = (im->yi < 0) ? -im->yi : 0;
im->yoff2 = (im->yf > win_h) ? (win_h - im->yf - 1) : 0;
#ifdef MTRACE
M_trace("PosImg", "xoff1=%d yoff1=%d", im->xoff1, im->yoff1);
#endif
}
/************* checks if position is ok ****************************/
static int
bad_position(IPTR im)
{
return ((im->xoff1 != 0 && (im->xoff1 + im->xi) != 0) ||
(im->yoff1 != 0 && (im->yoff1 + im->yi) != 0) ||
(im->xoff2 != 0 && (im->xoff2 + im->xf) != win_w - 1) ||
(im->yoff2 != 0 && (im->yoff2 + im->yf) != win_h - 1));
}
/*****************************************************************
* the global display function interface
*
*****************************************************************/
typedef enum
{
DS_INVALID = -1, /* forcing type to be of a signed type */
DS_BLOCK,
DS_DOWN,
DS_UP,
DS_LEFT,
DS_RIGHT,
DS_TBC,
DS_CTB,
DS_LRC,
DS_CLR,
DS_INT,
DS_CINT,
DS_GINT,
DS_REC1,
DS_REC2,
DS_SPRKL,
DS_FADE,
DS_CYC /* special: cyclr thru all of above */
} DS_MODE;
typedef struct
{
DS_MODE ds;
void (*dsfunc) (IPTR);
}
Disp;
static Disp disp[] =
{
{DS_BLOCK, ds_block},
{DS_DOWN, ds_down},
{DS_UP, ds_up},
{DS_LEFT, ds_left},
{DS_RIGHT, ds_right},
{DS_TBC, ds_tbc},
{DS_CTB, ds_ctb},
{DS_LRC, ds_lrc},
{DS_CLR, ds_clr},
{DS_INT, ds_int},
{DS_CINT, ds_cint},
{DS_GINT, ds_gint},
{DS_REC1, ds_rec1},
{DS_REC2, ds_rec2},
{DS_SPRKL, ds_sprkl},
{DS_FADE, ds_fade}
};
static int ndisp = sizeof(disp) / sizeof(disp[0]);
/****** funciton generates the option string *******/
const char *
gds_string(void)
{
return "Block|Down|Up|Left|Right|DownUp|UpDown|LR|RL|Int|CInt|"
"GInt|Rec1|Rec2|Sparkle|Fade|Cycle";
}
/******************************************************************
* Display the image defined in the IPTR structure
*****************************************************************/
static void
set_display_zoom(IPTR im)
{
if (g_zoomx < 0.1 || g_zoomy < 0.1)
{
zoomx = ((win_w + 100) / im->w);
zoomy = ((win_h + 100) / im->h);
zoomx = zoomy = Min(zoomx, zoomy);
if (zoomx < 0.1)
zoomx = zoomy = 1.0;
}
else
{
zoomx = g_zoomx;
zoomy = g_zoomy;
}
}
static int display_auto; /* so we can turn buy cursor off */
static int dstyle;
static void
refresh_display(IPTR i)
{
if (dstyle != DS_FADE && (double_buf || (win_h > i->h || win_w > i->w)))
clear_outside_rect(img_rect(i));
}
void
display_image(IPTR im, int ds_fancy, int pre_clean)
{
int ldstyle = ds_fancy;
if (!image_ready(im, "Display"))
return;
if (!display_auto)
show_busy("");
#ifdef MDEBUG
M_debug("DisplayImage", "Setting Mode");
#endif
if (ldstyle < 0 || ldstyle >= ndisp)
ldstyle = DS_BLOCK;
dstyle = ldstyle; /* center image uses dstyle */
/* Initialize CI&RGBA matrix */
rgba = im->mraster;
cind = im->mraster;
set_current_window(win_id);
reshapeviewport();
set_display_mode(im);
set_display_zoom(im);
/* If not centered , center it. */
if (im->w != (im->xf - im->xi + 1) || im->h != (im->yf - im->yi + 1))
{
update_image_info(im);
center_image(im, 2);
M_info("DisplayImage", "Centering Image");
}
if (bad_position(im))
positioning_image(im);
/*
* avoid repaint screen if possible, also if the display style is fade,
* must not clear screen
*/
M_info("DisplayImage", "Clearing Display");
if (pre_clean)
refresh_display(im);
pxi = im->xi + im->xoff1;
pxf = im->xf + im->xoff2;
px0 = -im->xi;
pyi = im->yi + im->yoff1;
pyf = im->yf + im->yoff2;
py0 = -im->yi;
set_current_window(win_id);
reshapeviewport();
if (dstyle == DS_BLOCK)
{
rectzoom(zoomx, zoomy);
}
else
{
swapbuffers(); /* show last clear_outside_rect */
refresh_display(im);
frontbuffer(1);
rectzoom(1.0, 1.0);
}
#ifdef MDEBUG
M_debug("DisplayImage", "Displaying with style=%d", (int) ldstyle);
#endif
(disp + ldstyle)->dsfunc(im);
end_busy();
frontbuffer(!double_buf);
}
/******************************************************************
* Similar to display_image but addtionally display text and
* other misc. stuff. Also the default display function
******************************************************************/
void
Generic_display(IPTR im, int ds_fancy, int pre_clean)
{
static int lfancy; /* counter. Dstyle is the current style */
long owin = winget();
/*
* it is possible that main window is not initialized if fit_image_size
* is requested
*/
open_main_window(im);
#ifdef MTRACE
M_trace("GenericDisplay", "Entering with ds_fancy=%d", ds_fancy);
#endif
if (ds_fancy >= ndisp)
ds_fancy = DS_CYC;
dstyle = (ds_fancy == DS_CYC) ? (++lfancy % ndisp) : ds_fancy;
/* interlace only if image is interlaced and not repaint (-1) */
if (im->interlace && ds_fancy >= 0)
dstyle = DS_GINT;
display_image(im, dstyle, pre_clean);
display_sgf(im);
display_text(im);
/*
* if ds_fancy > 0, frontbuffer & backbuffer already consistent as
* display_image turned frontbuffer true
*/
if (double_buf && dstyle <= 0)
{
swapbuffers();
/*
* in slideshow mode, we do not need to guarantee backbuffer
* consistency, which is relied upon in Text, C&P only.
*/
if (!slideshow)
{
display_auto = 1;
display_image(im, DS_BLOCK, pre_clean);
display_sgf(im);
display_text(im);
display_auto = 0;
}
}
set_current_window(owin);
#ifdef MTRACE
M_trace("GenericDisplay", "Exiting");
#endif
}
/************************************************************************
* xoff and yoff makes displaying large image a little faster. Note
* im->xf+im->xoff2 - im->xi+im->xoff1 + 1== im->w>win_w?win_w:im->w;
*
* xdir:0 for y direction 1 for x direction 3 for both
************************************************************************/
void
center_image(IPTR im, int xdir)
{
int w = im->w, h = im->h;
if (dstyle == DS_BLOCK)
{
w *= zoomx;
h *= zoomy;
}
if (xdir)
{
im->xi = (win_w - w) / 2;
#ifdef PWRITE_BUG
if ((im->xi + win_xo) <= 0)
im->xi = -win_xo + 1;
#endif
im->xf = im->xi + w - 1;
}
if (xdir == 2 || xdir == 0)
{
im->yi = (win_h - h) / 2;
im->yf = im->yi + h - 1;
}
#ifdef MDEBUG
M_debug("CenterImage", "xi=%d yi=%d", im->xi, im->yi);
#endif
positioning_image(im);
}
/********************************************************************
* Pan iamge so that the viewing area is not limited by the screen size.
* Code is so written to minimize the repaint if single buffer is used.
********************************************************************/
/*
* the buttons are numbered as the keypad
*/
int
image_pan(IPTR im, int x, int pstep)
{
int xvi[2], xvf[2], yvi[2], yvf[2];
int nc = 1;
int xi, xf, yi, yf;
static int last_center, min_keep = 100;
/*
* if image not ready, should be silently ignored because the pan button
* is a touch button
*/
if (!im->ok)
return -1;
xi = xvi[0] = xvi[1] = im->xi;
xf = xvf[0] = xvf[1] = im->xf;
yi = yvi[0] = yvi[1] = im->yi;
yf = yvf[0] = yvf[1] = im->yf;
switch (x)
{
case 1: /* left-down */
nc = 2;
yvi[0] = yf - pstep;
xvi[1] = xf - pstep;
yvf[1] = yf - pstep;
xi -= pstep;
yi -= pstep;
break;
case 2: /* down */
yvi[0] = yf - pstep;
yi -= pstep;
break;
case 3:
nc = 2;
yvi[0] = yf - pstep;
xvf[1] = xi + pstep;
yvf[1] = yf - pstep;
xi += pstep;
yi -= pstep;
break;
case 4:
xvi[0] = xf - pstep;
xi -= pstep;
break;
case 5:
if (!last_center)
{
center_image(im, 2);
xi = im->xi;
yi = im->yi;
}
else
nc = 0;
break;
case 6:
xvf[0] = xi + pstep;
xi += pstep;
break;
case 7:
nc = 2;
yvf[0] = yi + pstep;
xvi[1] = xf - pstep;
yvi[1] = yi + pstep;
xi -= pstep;
yi += pstep;
break;
case 8:
yvf[0] = yi + pstep;
yi += pstep;
break;
case 9:
nc = 2;
yvf[0] = yi + pstep;
yvi[1] = yi + pstep;
xvf[1] = xi + pstep;
xi += pstep;
yi += pstep;
break;
default:
Bark("ImagePan", bugquit); /* something is very wrong */
clean_up();
break;
}
if (nc)
{
xf = xi + im->w - 1;
yf = yi + im->h - 1;
if (xf < min_keep)
{
xf = min_keep;
xi = xf - im->w + 1;
}
if (xi > win_w - min_keep)
{
xi = win_w - min_keep;
xf = xi + im->w - 1;
}
if (yf < min_keep)
{
yf = min_keep;
yi = yf - im->h + 1;
}
if (yi > win_h - min_keep)
{
yi = win_h - min_keep;
yf = yi + im->h - 1;
}
im->xi = xi;
im->xf = xf;
im->yi = yi;
im->yf = yf;
positioning_image(im);
if (!(xi < 0 && yi < 0 && xf > win_w && yf > win_w))
{
rect_clear(win_id, xvi[0], xvf[0], yvi[0], yvf[0]);
if (nc > 1)
rect_clear(win_id, xvi[1], xvf[1], yvi[1], yvf[1]);
}
display_auto = 1;
im->io->display(im, -1, double_buf);
display_auto = 0;
}
last_center = (x == 5);
handle_wm_other(im);
fl_qenter(KEYBD, 2);
return 0;
}
/********************************************************************
* Auto pan
*******************************************************************/
#define PAN_CRIT 20 /* unviewable less than this is ignored */
void
auto_pan(IPTR im)
{
int dist, dist1, dist2, pstep;
int saveflag = always_clear;
if ((im->w - PAN_CRIT) < win_w && (im->h - PAN_CRIT) < win_h)
return;
/* pan only if requestd or in slides show */
if (always_pan == 0 || !(slideshow && always_pan == 1))
return;
msleep(500); /* take a look at it */
display_auto = 1; /* turn busy cursor off */
pstep = 4; /* smaller steps looks nicer */
always_clear = 0; /* do not clear screen */
dist1 = Abs(im->xoff1);
dist2 = Abs(im->xoff2);
for (dist = dist1; dist > 0; dist -= pstep)
image_pan(im, 6, pstep);/* move right */
check_emergency(); /* service any Q event */
msleep(500);
for (dist = dist1 + dist2; dist > 0; dist -= pstep)
image_pan(im, 4, pstep);/* move left */
check_emergency();
msleep(500);
for (dist = dist2; dist > 0; dist -= pstep)
image_pan(im, 6, pstep);/* move right */
check_emergency();
msleep(500);
/* image now is at about the same postion as before */
dist1 = Abs(im->yoff1);
dist2 = Abs(im->yoff2);
for (dist = dist1; dist > 0; dist -= pstep)
image_pan(im, 8, pstep);/* move up */
check_emergency();
for (dist = dist1 + dist2; dist > 0; dist -= pstep)
image_pan(im, 2, pstep);/* move down */
check_emergency();
msleep(500);
/* the corner still not seen, forget it */
for (dist = dist2; dist > 0; dist -= 2 * pstep)
image_pan(im, 8, 2 * pstep); /* move up */
/* center both dir */
image_pan(im, 5, 10);
display_auto = 0;
always_clear = saveflag;
}
#if 0 /* No longer used **{* */
/*************************************************************
* Rectcopy is similar to rectcopy except that it optionally
* does raster move in core image. However, zooming is
* not obeyed.
************************************************************/
static int rascp;
void
set_rectcp_ras(int y)
{
rascp = y;
}
void
Rectcopy(int xi, int yi, int xf, int yf, int nx, int ny)
{
IPTR im = imgptr;
void *pp;
Rect_t des, src;
const Rect_t *ir, *uu;
frontbuffer(1);
rectcopy(xi, yi, xf, yf, nx, ny);
frontbuffer(!double_buf);
if (rascp)
{
int w, h;
ir = img_rect(im);
/* the src raster: clip to the image boundary */
if (!(uu = union_rect(make_rect(xi, yi, xf - xi + 1, yf - yi + 1), ir)))
return;
copy_rect(&src, uu);
/* find destination, taking into account of src clipping */
nx += (src.x - xi);
ny += (src.y - yi);
copy_rect(&des, make_rect(nx, ny, src.w, src.h));
/* clip to the image boundary */
if (!(uu = union_rect(&des, ir)))
return;
copy_rect(&des, uu);
w = Min(src.w, des.w);
h = Min(src.h, des.h);
des.w = src.w = w;
des.h = src.h = h;
if ((pp = get_subimage(im, src.x, src.y, src.w, src.h)))
{
put_subimage(im, pp, &des, 1);
free_mat(pp);
}
}
}
#endif /* disabling Rectcopy } */
/**********************************************************
* allow only certain number of bits in raster. This is necessary
* because the raster might come from framebuffer read, which
* is 12bits on most machines while CMAPBITS is less than 12
************************************************************/
void
do_ci_mask(register ci_t *ras, unsigned total,
register unsigned int mask)
{
register ci_t *rs = ras + total;
int m = power_of_2(mask);
/* need to make sure that mask is full bits */
mask = (m > MAXCML ? MAXCML : m) - 1;
for (; ras < rs; ras++)
*ras &= mask;
}
/*
* intended primarily to read the main screen
*/
int
read_screen(IPTR im, int x, int y, int w, int h)
{
long owin = winget();
M_info("ReadScr", "Performing screen read");
im->xi = x;
im->yi = y;
im->xf = im->xi + w - 1;
im->yf = im->yi + h - 1;
im->w = w;
im->h = h;
set_current_window(win_id);
reshapeviewport();
im->ok = (img_get_rastermem(im) < 0) ? 0 :
Rectread(im->xi, im->yi, im->xf, im->yf, im->raster) > 0;
set_current_window(owin);
return im->ok;
}